﻿using System;
using System.Collections.Generic;
using System.Text;

namespace HtmlParser
{
    /// <summary>
    /// Definition Class Html Tag
    /// </summary>
    public class HtmlTag
    {
        #region Fields
        private string m_tagName;
        protected List<Attribute> m_attributes = new List<Attribute>();
        #endregion

        #region Constructor
        /// <summary>
        /// Initializes a new instance of the <see cref="HtmlTag"/> class.
        /// </summary>
        /// <param name="tagName">Name of the tag.</param>
        public HtmlTag(string tagName)
        {
            this.m_tagName = tagName;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="HtmlTag"/> class.
        /// </summary>
        public HtmlTag()
        {

        }
        #endregion

        #region Properties
        /// <summary>
        /// Get the Name of the Tag
        /// </summary>
        /// <value>The name of the tag.</value>
        public String TagName
        {
            get { return this.m_tagName; }
            set
            {
                this.m_tagName = value;
            }
        }

        /// <summary>
        /// Gets the tag id.
        /// </summary>
        /// <value>The tag id.</value>
        public string TagId
        {
            get
            {
                string tagId = string.Empty;
                foreach (Attribute attribute in m_attributes)
                {
                    if (attribute.Name.ToLower() == "id")
                    {
                        tagId = attribute.Value;
                        break;
                    }
                }
                return tagId;
            }
        }

        /// <summary>
        /// Check if the Tag is the End tag
        /// </summary>
        public TagType IsEndTag
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the attributes.
        /// </summary>
        /// <value>The attributes.</value>
        public List<Attribute> Attributes
        {
            get
            {
                return m_attributes;
            }
        }

        /// <summary>
        /// Gets or sets the name of the domain.
        /// </summary>
        /// <value>
        /// The name of the domain.
        /// </value>
        public string DomainName
        {
            get;
            set;
        }
        #endregion

        #region Method
        /// <summary>
        /// Adds the attribute.
        /// </summary>
        /// <param name="atribute">The atribute.</param>
        public void AddAttribute(Attribute atribute)
        {
            if (atribute != null)
            {
                m_attributes.Add(atribute);
            }
        }

        /// <summary>
        /// Adds the attribute.
        /// </summary>
        /// <param name="attributes">The attributes.</param>
        public void AddAttribute(List<Attribute> attributes)
        {
            m_attributes.AddRange(attributes);
        }

        /// <summary>
        /// Returns a <see cref="System.String"/> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            if (IsEndTag == TagType.Close)
            {
                return string.Format("</{0}>", TagName);
            }
            StringBuilder result = new StringBuilder();
            result.Append(string.Format("<{0} ", TagName));

            foreach (Attribute attribute in m_attributes)
            {
                result.Append(attribute.ToString());
                result.Append(" ");
            }

            if (IsEndTag == TagType.OpenClose)
            {
                result.Append(" />");
            }
            else
            {
                result.Append(">");
            }
            return result.ToString();
        }

        /// <summary>
        /// Toes the string without attribute.
        /// </summary>
        public virtual string ToStringWithoutAttribute()
        {
            if (IsEndTag == TagType.Close)
            {
                return string.Format("</{0}>", TagName);
            }
            if (IsEndTag == TagType.OpenClose)
            {
                return string.Format("<{0}/>", TagName);
            }
            return string.Format("<{0}>", TagName);
        }

        /// <summary>
        /// Toes the string without formated.
        /// </summary>
        /// <returns></returns>
        public virtual string ToStringWithoutFormated()
        {
            return string.Empty;
        }

        /// <summary>
        /// Checks the URL contains domain.
        /// </summary>
        /// <returns></returns>
        protected bool CheckUrlContainsDomainName()
        {
            foreach (Attribute attribute in Attributes)
            {
                if (attribute.Name.ToLower() == "src" &&
                    (attribute.Value.ToLower().Contains("http://") ||
                    (attribute.Value.ToLower().Contains("ftp://")) ||
                    (attribute.Value.ToLower().Contains("https://")) ||
                     attribute.Value.ToLower().Contains("www")))
                {
                    return true;
                }
            }
            return false;
        }
        #endregion
    }


    /// <summary>
    /// The Tag for content 
    /// </summary>
    public class HtmlContent : HtmlTag
    {
        /// <summary>
        /// Gets or sets the content.
        /// </summary>
        /// <value>The content.</value>
        public string Content
        {
            get;
            private set;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="HtmlContent"/> class.
        /// </summary>
        public HtmlContent(string content)
        {
            IsEndTag = TagType.OpenClose;
            Content = content;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="HtmlContent"/> class.
        /// </summary>
        public HtmlContent()
        {
            IsEndTag = TagType.OpenClose;
            Content = string.Empty;
        }

        /// <summary>
        /// Returns a <see cref="System.String"/> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            return Content;
        }

        /// <summary>
        /// Toes the string without attribute.
        /// </summary>
        /// <returns></returns>
        public override string ToStringWithoutAttribute()
        {
            return Content;
        }

        /// <summary>
        /// Toes the string without formated.
        /// </summary>
        /// <returns></returns>
        public override string ToStringWithoutFormated()
        {
            return Content;
        }
    }


    /// <summary>
    /// 
    /// </summary>
    public class ImgTag : HtmlTag
    {
        /// <summary>
        /// Returns a <see cref="System.String"/> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            if(CheckUrlContainsDomainName())
            {
               return base.ToString();
            }

            if (IsEndTag == TagType.Close)
            {
                return string.Format("</{0}>", TagName);
            }
            StringBuilder result = new StringBuilder();
            result.Append(string.Format("<{0} ", TagName));

            foreach (Attribute attribute in m_attributes)
            {
                if(attribute.Name.ToLower()=="src")
                {
                    if (attribute.Delim == (char)0)
                    {
                        result.Append(string.Format("src={0} ",attribute.Value.TrimStart('/')));
                    }
                    else
                    {
                        result.Append(string.Format("src={0}{1}{2}{0} ",attribute.Delim,DomainName,attribute.Value.TrimStart('/')));
                    }
                }
                else
                {
                    result.Append(attribute.ToString());
                    result.Append(" ");    
                }
            }

            if (IsEndTag == TagType.OpenClose)
            {
                result.Append(" />");
            }
            else
            {
                result.Append(">");
            }
            return result.ToString();

        }

        /// <summary>
        /// Toes the string without attribute.
        /// </summary>
        /// <returns></returns>
        public override string ToStringWithoutAttribute()
        {
            return ToString();
        }

        /// <summary>
        /// Toes the string without formated.
        /// </summary>
        /// <returns></returns>
        public override string ToStringWithoutFormated()
        {
            return ToString();
        }

    }

    public class Embed : HtmlTag
    {
        public override string ToString()
        {
            return base.ToString();
        }
        public override string ToStringWithoutAttribute()
        {
            return ToString();
        }
        public override string ToStringWithoutFormated()
        {
            return ToString();
        }
    }


    /// <summary>
    /// 
    /// </summary>
    public class AnchorTag :HtmlTag
    {
        /// <summary>
        /// Returns a <see cref="System.String"/> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            if (CheckUrlContainsDomainName())
            {
                return base.ToString();
            }
            string domainName = DomainName;
            if (IsEndTag == TagType.Close)
            {
                return string.Format("</{0}>", TagName);
            }
            StringBuilder result = new StringBuilder();
            result.Append(string.Format("<{0} ", TagName));

            foreach (Attribute attribute in m_attributes)
            {
                if (attribute.Name.ToLower() == "href")
                {
                    if (attribute.Delim == (char)0)
                    {
                        result.Append(string.Format("href={0} ", attribute.Value));
                    }
                    else
                    {
                        result.Append(string.Format("href={0}{1}{2}{0} ", attribute.Delim, domainName, attribute.Value));
                    }
                }
                else
                {
                    result.Append(attribute.ToString());
                    result.Append(" ");
                }
            }

            if (IsEndTag == TagType.OpenClose)
            {
                result.Append(" />");
            }
            else
            {
                result.Append(">");
            }
            return result.ToString();

        }
    }


    /// <summary>
    /// 
    /// </summary>
    public enum TagType
    {
        /// <summary>
        /// Is OpenTag
        /// </summary>
        Open,
        /// <summary>
        /// Open Tag also is Close tag
        /// </summary>
        OpenClose,
        /// <summary>
        /// Close tag only
        /// </summary>
        Close
    }
}
